package tools

import (
	"fmt"
	"net/http"
)

// RedirectResult 用于存储请求的结果，包括最终的响应和重定向链
type RedirectResult struct {
	FinalURL      string         // 最终的 URL（重定向链结束后的 URL）
	StatusCode    int            // 最终的响应状态码
	RedirectChain []RedirectInfo // 重定向链的详细记录
}

// RedirectInfo 记录重定向过程中的一次跳转信息
type RedirectInfo struct {
	URL        string // 请求的 URL
	StatusCode int    // 该次请求得到的状态码 (如 301)
}

// GetWithRedirectTrace 发起 GET 请求并跟踪重定向过程
func GetWithRedirectTrace(rawURL string) (string, error) {

	result := RedirectResult{}
	// 初始化一个重定向信息切片，预分配少量空间以避免不必要的内存分配
	redirectChain := make([]RedirectInfo, 0, 3)

	// 1. 创建自定义的 HTTP Client
	client := &http.Client{
		// 2. 关键：自定义 CheckRedirect 策略
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			// 这个函数在每次即将发生重定向前被调用
			// `via` 是已经发生的一系列请求（当前请求是下一个）

			// 记录最后一次重定向请求的信息（即当前请求的来源）
			// len(via)-1 是上一次请求的索引
			prevReq := via[len(via)-1]
			// 记录上一次请求的 URL 和它收到的响应状态码
			// http.StatusMovedPermanently 就是 301
			redirectInfo := RedirectInfo{
				URL:        prevReq.URL.String(),
				StatusCode: req.Response.StatusCode, // 注意：这里记录的是响应状态码
			}
			redirectChain = append(redirectChain, redirectInfo)

			// 如果重定向次数过多，可以在此停止，这里我们允许默认的最大次数（10次）
			if len(via) >= 10 {
				return fmt.Errorf("too many redirects")
			}
			return nil // 返回 nil 继续重定向流程
		},
	}

	// 3. 创建请求
	req, err := http.NewRequest("GET", rawURL, nil)
	if err != nil {
		return "", err
	}
	// 设置请求头，模拟浏览器访问以避免被某些服务器拒绝
	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36")

	// 4. 发起请求
	// 由于设置了 CheckRedirect，客户端会自动处理重定向，直到返回 200 或错误
	resp, err := client.Do(req)
	if err != nil {
		// 即使有错误（如过多重定向），也可能已经记录了部分重定向链
		result.RedirectChain = redirectChain
		return "", err
	}
	defer resp.Body.Close() // 确保关闭响应体

	// 5. 收集最终结果
	result.FinalURL = resp.Request.URL.String() // 最终请求的 URL
	result.StatusCode = resp.StatusCode         // 最终的状态码
	result.RedirectChain = redirectChain        // 中间的重定向链

	return result.FinalURL, nil
}
